home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 050 / tpstuff1.arc / LONGINT.PAS < prev    next >
Pascal/Delphi Source File  |  1985-10-28  |  22KB  |  406 lines

  1. {
  2.   Long integer arithmatic package:
  3.   This set of subroutines allow you to compute with integers in the
  4.   range of +2,147,483,647 to -2,147,483,648.
  5.  
  6.   Long integers are stored as four bytes (or two words) and are defined by
  7.   the long type.
  8.  
  9.   Long integers can be initialized either from a string with optionally
  10.   a sign and one to ten digits via the routine atol.  The string must be
  11.   of type longstr.
  12.  
  13.   Further, the routine itol allows you to initialize a long from an integer.
  14.  
  15.   Finally, some DOS functions return long integers.
  16.  
  17.   Long integers are converted to strings for display via the ltoa routine.
  18.   It returns a string with the type of longstr.
  19.  
  20.   Performance testing indicates that these routines are typically
  21.   70% faster and require half the memory as equivilent functions
  22.   coded directly in TURBO Pascal.
  23.  
  24.   See listings for calling details.
  25. }
  26. {;                                                                        }
  27. {; Copyright (c) 1984 Thomas J. Foth                                      }
  28. {; All Rights Reserved                                                    }
  29. {;                                                                        }
  30. {; Permission is granted to freely distribute this code, but not for      }
  31. {; profit and provided that the following address and disclaimer are      }
  32. {; included.                                                              }
  33. {;                                                                         }
  34. {; Portions of this program may be used freely, in other works, provided   }
  35. {; that credit to the author and this work appear with the portions used.  }
  36. {;                                                                         }
  37. {; The author's address:                                                   }
  38. {;                                                                         }
  39. {; Thomas J. Foth                                                          }
  40. {; 260 Sunset Ave.                                                         }
  41. {; Fairfield, CT 06430                                                     }
  42. {; (203) 334-6401                                                          }
  43. {;                                                                         }
  44. {; Disclaimer:                                                             }
  45. {;                                                                         }
  46. {; This program is provided "as-is" without warranty of any kind, either   }
  47. {; expressed or implied, including, but not limited to the implied         }
  48. {; warranties of merchantability and fitness for a particular purpose.     }
  49. {;                                                                         }
  50.  
  51. type long = record
  52.              loword : integer;
  53.              hiword : integer;
  54.             end;
  55.      longstr = string[11];
  56.  
  57. procedure itol(n1:integer;var n2:long);
  58. { Convert signed to integer n1 to signed long n2 }
  59.  begin;
  60.   n2.loword := n1;
  61.   if n1 >= 0 then n2.hiword := 0
  62.              else n2.hiword := -1;
  63.  end;
  64.  
  65. procedure addl(var sum:long;n1,n2:long);
  66. { Add long n1 to n2 producing sum: may be treated as signed }
  67. { or unsigned                                               }
  68.  Begin;
  69.   inline
  70.    ($8B/$86/n1/         { MOV AX,n1[bp]    }
  71.     $03/$86/n2/         { ADD AX,n2[bp]    }
  72.     $C4/$BE/sum/        { LES DI,sum[BP]   }
  73.     $26/$89/$05/        { MOV ES:[DI],AX   }
  74.     $BF/$02/$00/        { MOV DI,2         }
  75.     $8B/$83/n1/         { MOV AX,n1[di+bp] }
  76.     $13/$83/n2/         { ADC AX,n2[di+bp] }
  77.     $C4/$BE/sum/        { LES DI,sum[BP]   }
  78.     $26/$89/$45/$02);   { MOV ES:[DI]+2,AX }
  79.  end;
  80.  
  81. procedure subl(var diff:long;n1,n2:long);
  82. { subtract long n2 from n1 producing diff: may be treated as signed }
  83. { or unsigned                                                       }
  84.  Begin;
  85.   inline
  86.    ($8B/$86/n1/         { MOV AX,n1[bp]    }
  87.     $2B/$86/n2/         { SUB AX,n2[bp]    }
  88.     $C4/$BE/diff/       { LES DI,diff[BP]  }
  89.     $26/$89/$05/        { MOV ES:[DI],AX   }
  90.     $BF/$02/$00/        { MOV DI,2         }
  91.     $8B/$83/n1/         { MOV AX,n1[di+bp] }
  92.     $1B/$83/n2/         { SBB AX,n2[di+bp] }
  93.     $C4/$BE/diff/       { LES DI,diff[BP]  }
  94.     $26/$89/$45/$02);   { MOV ES:[DI]+2,AX }
  95.  end;
  96.  
  97. function cmpl(n1: long; op:longstr; n2:long): boolean;
  98.  
  99. { compares long n1 with n2 returning boolean: may be treated as signed }
  100. { or unsigned. op is a string like '>', '<', '=>', '=<', '>=', '<=',   }
  101. { or '='.  '<>' is NOT supported: use NOT(cmpl(n1,'=',n2)) instead.    }
  102.  var bool: boolean;
  103.  Begin;
  104.   inline (
  105.     $8B/$86/n1/         { MOV AX,n1[bp]    }
  106.     $2B/$86/n2/         { SUB AX,n2[bp]    low order word difference}
  107.     $BF/$02/$00/        { MOV DI,2         point to high order words}
  108.     $8B/$9B/n1/         { MOV BX,n1[di+bp] }
  109.     $1B/$9B/n2/         { SBB BX,n2[di+bp] high order word difference}
  110.     $30/$ED/            { XOR CH,CH        }
  111.     $8A/$8E/op/         { MOV CL,op[bp]    get the string length}
  112.     $8D/$B6/op/         { LEA SI,op[bp]    }
  113.     $46/                { INC SI           point to the first operator}
  114.     $C6/$86/bool/$00/   { MOV bool[bp],false assume false}
  115.     $E3/$36/            { jcxz exit        no opeators: false}
  116.                         { tstops:          }
  117.     $36/$80/$3C/$3D/    { cmp byte ptr ss:[si],'='}
  118.     $75/$0A/            { jne opt1         not an equal sign}
  119.     $09/$DB/            { or  bx,bx        }
  120.     $75/$22/            { jnz nxtop        not zero: can't be true}
  121.     $09/$C0/            { or  ax,ax        }
  122.     $75/$1E/            { jnz nxtop        not zero: can't be true}
  123.     $EB/$21/            { jmp true         hi & lo zero: true     }
  124.                         { opt1:            }
  125.     $36/$80/$3C/$3E/    { cmp byte ptr ss:[si],'>'}
  126.     $75/$0C/            { jne  opt2        not a greater than sign}
  127.     $09/$DB/            { or   bx,bx       }
  128.     $78/$12/            { js   nxtop       neg. difference means less than}
  129.     $75/$15/            { jnz  true        pos. difference means greater than}
  130.     $09/$C0/            { or   ax,ax       }
  131.     $75/$11/            { jnz  true        pos. difference means greater than}
  132.     $EB/$0A/            { jmp  nxtop       no difference means equal}
  133.                         { opt2:            }
  134.     $36/$80/$3C/$3C/    { cmp byte ptr ss:[si],'<'}
  135.     $75/$0E/            { jne  exit        invalid operator is false}
  136.     $09/$DB/            { or   Bx,Bx       }
  137.     $78/$05/            { js   true        neg. difference means less than}
  138.                         { nxtop:           }
  139.     $46/                { INC SI           point to next operator}
  140.     $E2/$D1/            { LOOP tstops      test until true or no more operators}
  141.     $EB/$05/            { JMP  EXIT        true not found: exit false}
  142.                         { true:            }
  143.     $C6/$86/bool/$01);  { MOV  bool[bp],true set true}
  144.                         { exit:            }
  145.     cmpl:=bool;
  146.  end;
  147.  
  148. procedure divl(var quo,rem:integer;n1:long;n2:integer);
  149. { Divides signed integer n2 into signed long n2, yielding signed    }
  150. { integer quotient quo and signed integer remainder rem             }
  151.  Begin;
  152.   inline
  153.    ($8B/$86/n1/         { MOV AX,n1[bp]    }
  154.     $BF/$02/$00/        { MOV DI,2         }
  155.     $8B/$93/n1/         { MOV DX,n1[bp+di] }
  156.     $8B/$8E/n2/         { MOV CX,n2[bp]    }
  157.     $F7/$F9/            { IDIV CX          }
  158.     $C4/$BE/quo/        { LES DI,quo[bp]   }
  159.     $26/$89/$05/        { MOV ES:[DI],AX   }
  160.     $C4/$BE/rem/        { LES DI,rem[bp]   }
  161.     $26/$89/$15);       { MOV ES:[DI],DX   }
  162.  end;
  163.  
  164. procedure multl(var prod:long;n1,n2:integer);
  165. { Multiplies signed integer n2 by signed integer n2, producing signed }
  166. { long prod.                                                          }
  167.  Begin;
  168.   inline
  169.    ($8B/$86/n1/         { MOV AX,n1[bp]    }
  170.     $8B/$8E/n2/         { MOV CX,n2[bp]    }
  171.     $F7/$E9/            { IMUL CX          }
  172.     $C4/$BE/prod/       { LES DI,prod[bp]  }
  173.     $26/$89/$05/        { MOV ES:[DI],AX   }
  174.     $26/$89/$55/$02);   { MOV ES:[DI+2],DX }
  175.  end;
  176.  
  177. procedure slrl(var quo:long;shift:integer);
  178. { Shifts quo by number of bits in 'shift' right, filling vacated bits }
  179. { left with zeros.                                                    }
  180.  Begin;
  181.   inline (
  182.     $cd/$02/
  183.     $8B/$8E/shift/      { MOV CX,shift[bp] }
  184.     $09/$C9/            { OR  CX,CX        }
  185.     $74/$18/            { JZ  END          }
  186.     $C4/$BE/quo/        { LES DI,quo[bp]   }
  187.     $26/$8B/$05/        { MOV AX,ES:[DI]   }
  188.     $26/$8B/$55/$02/    { MOV DX,ES:[DI+2] }
  189.     $D1/$EA/            { SHIFT: SHR DX    }
  190.     $D1/$D8/            { RCR AX           }
  191.     $E2/$FA/            { LOOP SHIFT       }
  192.     $26/$89/$05/        { MOV ES:[DI],AX   }
  193.     $26/$89/$55/$02);   { MOV ES:[DI+2],DX }
  194.                         { END:             }
  195.  end;
  196.  
  197. procedure sarl(var quo:long;shift:integer);
  198. { Shifts long by number fo bits in 'shift' right, propagating the sign bit.}
  199.  Begin;
  200.   inline (
  201.     $cd/$02/
  202.     $8B/$8E/shift/      { MOV CX,shift[bp] }
  203.     $09/$C9/            { OR  CX,CX        }
  204.     $74/$18/            { JZ  END          }
  205.     $C4/$BE/quo/        { LES DI,quo[bp]   }
  206.     $26/$8B/$05/        { MOV AX,ES:[DI]   }
  207.     $26/$8B/$55/$02/    { MOV DX,ES:[DI+2] }
  208.     $D1/$FA/            { SHIFT: SAR DX    }
  209.     $D1/$D8/            { RCR AX           }
  210.     $E2/$FA/            { LOOP SHIFT       }
  211.     $26/$89/$05/        { MOV ES:[DI],AX   }
  212.     $26/$89/$55/$02);   { MOV ES:[DI+2],DX }
  213.                         { END:             }
  214.  end;
  215.  
  216. procedure slll(var quo:long;shift:integer);
  217. { Shifts long by number fo bits in 'shift' left, filling vacated bits on }
  218. { right with zeros.                                                      }
  219.  Begin;
  220.   inline (
  221.     $cd/$02/
  222.     $8B/$8E/shift/      { MOV CX,shift[bp] }
  223.     $09/$C9/            { OR  CX,CX        }
  224.     $74/$18/            { JZ  END          }
  225.     $C4/$BE/quo/        { LES DI,quo[bp]   }
  226.     $26/$8B/$05/        { MOV AX,ES:[DI]   }
  227.     $26/$8B/$55/$02/    { MOV DX,ES:[DI+2] }
  228.     $D1/$E0/            { SHIFT: SHL AX    }
  229.     $D1/$D2/            { RCL DX           }
  230.     $E2/$FA/            { LOOP SHIFT       }
  231.     $26/$89/$05/        { MOV ES:[DI],AX   }
  232.     $26/$89/$55/$02);   { MOV ES:[DI+2],DX }
  233.                         { END:             }
  234.  end;
  235.  
  236. function ltoa(long:long): longstr;
  237. { Converts a long to signed printable ASCII string }
  238.  var temps :array[1..5] of char;
  239.      strg  :longstr;
  240.  Begin;
  241.   inline(
  242.  $1E/             {         PUSH    DS                                      }
  243.  $FC/             {         CLD                    Set direction Forward    }
  244.  $8C/$D0/         {         MOV     AX,SS                                   }
  245.  $8E/$C0/         {         MOV     ES,AX                                   }
  246.  $8E/$D8/         {         MOV     DS,AX                                   }
  247.  $32/$C0/         {         XOR     AL,AL          Clear AX                 }
  248.  $8D/$BE/temps/   {         LEA     DI,TEMPS[BP]   Point to working storage }
  249.  $B9/$05/$00/     {         MOV     CX,5           Five bytes               }
  250.  $AA/             {CLEAR:   STOS    BYTE PTR [DI]  Clear temp variables     }
  251.  $E2/$FD/         {         LOOP    CLEAR           -all of them            }
  252.  $B9/$20/$00/     {         MOV     CX,32          32 bits to convert       }
  253.  $8B/$9E/long/    {         MOV     BX,LONG[BP]    Load low order word      }
  254.  $BF/$02/$00/     {         MOV     DI,2           ... and ...              }
  255.  $8B/$93/long/    {         MOV     DX,LONG[BP+DI] hi order word            }
  256.  $F7/$C2/$00/$80/ {         TEST    DX,$8000       Negative?                }
  257.  $74/$0A/         {         JZ      NOCOMP         Nope                     }
  258.  $F7/$D2/         {         NOT     DX             1's Complement           }
  259.  $F7/$D3/         {         NOT     BX             Both                     }
  260.  $83/$C3/$01/     {         ADD     BX,1           Add 1                    }
  261.  $83/$D2/$00/     {         ADC     DX,0           Carry over               }
  262.  $FD/             {NOCOMP:  STD                    Set direction backward   }
  263.  $51/             {BITLOOP: PUSH    CX             Save bit counter         }
  264.  $B9/$05/$00/     {         MOV     CX,5           Five bytes = ten digits  }
  265.  $8D/$B6/temps/   {         LEA     SI,TEMPS[BP]   Set Indices              }
  266.  $83/$C6/$04/     {         ADD     SI,4           -end of ws               }
  267.  $8B/$FE/         {         MOV     DI,SI                                   }
  268.  $D1/$E3/         {         SHL     BX,1           Get a Bit                }
  269.  $D1/$D2/         {         RCL     DX,1           Rotate through all bits  }
  270.  $AC/             {BITADD:  LODSB                  Get a byte               }
  271.  $12/$C0/         {         ADC     AL,AL          Double adding in carry   }
  272.  $27/             {         DAA                    Packed adjust            }
  273.  $AA/             {         STOSB                  Save it                  }
  274.  $E2/$F9/         {         LOOP    BITADD         for another two digits   }
  275.  $59/             {         POP     CX             get bit counter          }
  276.  $E2/$E5/         {         LOOP    BITLOOP        another bit              }
  277.  $FC/             {         CLD                    Go forward               }
  278.  $8D/$BE/strg/    {         LEA     DI,strg[bp]    Point to string          }
  279.  $47/             {         INC     DI             Point to character       }
  280.  $33/$D2/         {         XOR     DX,DX          Clear DX - length counter}
  281.  $BE/$02/$00/     {         MOV     SI,2           Offset to hi order       }
  282.  $F7/$82/long/    {         TEST    LONG[BP+SI],8000  Negative?             }
  283.  $00/$80/
  284.  $74/$04/         {         JZ      NOSIGNED       Nope                     }
  285.  $42/             {         INC     DX             Set length               }
  286.  $B0/$2D/         {         MOV     AL,'-'         Make it minus            }
  287.  $AA/             {         STOSB                  save it                  }
  288.  $8D/$B6/temps/   {UNSIGNED:LEA     SI,TEMPS[BP]   Point to working storage }
  289.  $B9/$0A/$00/     {         MOV     CX,10          Ten bytes                }
  290.  $33/$DB/         {         XOR     BX,BX          Clear BX - length counter}
  291.  $F7/$C1/$01/$00/ {UNPK:    TEST    CX,1           High order?              }
  292.  $75/$0D/         {         JNZ     LOWNIB         nope                     }
  293.  $AC/             {         LODSB                  Get packed characters    }
  294.  $8A/$E0/         {         MOV     AH,AL                                   }
  295.  $D0/$E8/         {         SHR     AL,1           Hi nibble to Low nibble  }
  296.  $D0/$E8/         {         SHR     AL,1                                    }
  297.  $D0/$E8/         {         SHR     AL,1                                    }
  298.  $D0/$E8/         {         SHR     AL,1                                    }
  299.  $EB/$04/         {         JMP     OUTSTR         Go process a byte        }
  300.  $8A/$C4/         {LOWNIB:  MOV     AL,AH          Do the low nibble        }
  301.  $24/$0F/         {         AND     AL,0FH                                  }
  302.  $A8/$0F/         {OUTSTR:  TEST    AL,0FH         Is this a zero           }
  303.  $75/$04/         {         JNZ     OUTDIGIT       Nope                     }
  304.  $09/$DB/         {         OR      BX,BX          Have we leading nonzeroes}
  305.  $74/$04/         {         JZ      NXTNIB         nope                     }
  306.  $43/             {OUTDIGIT:INC     BX             keep track of length     }
  307.  $0C/$30/         {         OR      AL,'0'         Make it printable        }
  308.  $AA/             {         STOSB                  save it                  }
  309.  $E2/$DB/         {NXTNIB:  LOOP    UNPK           Do it again              }
  310.  $01/$D3/         {         ADD     BX,DX          Get length: is there any?}
  311.  $75/$04/         {         JNZ     SAVLEN         Yep                      }
  312.  $43/             {         INC     BX             Set length               }
  313.  $B0/$30/         {         MOV     AL,'0'         Make it zero             }
  314.  $AA/             {         STOSB                  save it                  }
  315.  $8D/$BE/strg/    {SAVLEN:  LEA     DI,strg[bp]    Point to string          }
  316.  $36/$88/$1D/     {         MOV     SS:[DI],BL     Save length              }
  317.  $1F);            {         POP     DS                                      }
  318.  
  319.  ltoa:=strg;      { We can't reference ltoa in inline(), so we do this.     }
  320.  
  321.  end;
  322.  
  323.  
  324. procedure atol(strg: longstr; var val:long; var rc: integer);
  325. begin;
  326. inline(
  327.  
  328. { This function mimics the Turbo val() procedure: strg is a one to   }
  329. { 11 character string with an optional leading sign (atol accepts a  }
  330. { leading '+' or '-' sign, val() only accepts a leading '-' sign).   }
  331. { val is the long to receive the value.  rc is 0 if the string is    }
  332. { a null or contains a valid numeric.  Else, rc is the point at which}
  333. { a nonnumeric was found, or the digit that caused val to overflow.  }
  334. { like Turbo val() trailing or leading spaces are not allowed.       }
  335. { atol accepts longs in the rangs +2,147,483,647 to -2,147,483,647.  }
  336. { -2,147,483,648 generates an error. val() returns an error for      }
  337. { -32,768.                                                           }
  338.  
  339.  $33/$C0          {XOR     AX,AX      ;Clear accum                   }
  340. /$33/$D2          {XOR     DX,DX      ; ...and ext                   }
  341. /$32/$ED          {XOR     CH,CH      ; and hi cnt                   }
  342. /$33/$F6          {XOR     SI,SI      ; set rc if no chars           }
  343. /$8A/$8E/strg     {MOV     CL,[strg+BP]; get length                  }
  344. /$E3/$6D          {JCXZ    EXIT       ; return if no length          }
  345. /$8D/$BE/strg     {LEA     DI,[strg+bp]; point to string             }
  346. /$47              {INC     DI         ; point to first char          }
  347. /$BE/$FF/$FF      {MOV     SI,-1      ; Flag negative                }
  348. /$36/$80/$3D/$2D  {CMP     BYTE PTR SS:[DI],'-'; Minus sign?         }
  349. /$74/$3F          {JE      NXTCHR     ; Make negative                }
  350. /$BE/$01/$00      {MOV     SI,1       ; Assume positive              }
  351. /$36/$80/$3D/$2B  {CMP     BYTE PTR SS:[DI],'+'; Plus sign?          }
  352. /$74/$36          {JE      NXTCHR     ; go look at next char         }
  353.                   {CHKCHR:                                           }
  354. /$36/$80/$3D/$30  {CMP     BYTE PTR SS:[DI],'0'; Numeric?            }
  355. /$7C/$38          {JL      ENDSTR     ; Nope                         }
  356. /$36/$80/$3D/$39  {CMP     BYTE PTR SS:[DI],'9';                     }
  357. /$7F/$32          {JG      ENDSTR     ; Nope                         }
  358. /$BB/$0A/$00      {MOV     BX,000A    ; Base value                   }
  359. /$50              {PUSH    AX         ; Save low order               }
  360. /$8B/$C2          {MOV     AX,DX      ; Get high order               }
  361. /$F7/$E3          {MUL     BX         ; Shift it                     }
  362. /$70/$28          {JO      ENDSTR     ; Too big: error.              }
  363. /$78/$26          {JS      ENDSTR                                    }
  364. /$8B/$D0          {MOV     DX,AX      ; Temp Store Hi order          }
  365. /$58              {POP     AX         ; Restore low order            }
  366. /$52              {PUSH    DX         ; Save Hi order                }
  367. /$F7/$E3          {MUL     BX         ; Shift low order              }
  368. /$5B              {POP     BX         ; Get low order                }
  369. /$03/$D3          {ADD     DX,BX      ; Add it                       }
  370. /$78/$1B          {JS      ENDSTR     ; Too big, exit.               }
  371. /$72/$19          {JC      ENDSTR                                    }
  372. /$36/$8A/$1D      {MOV     BL,BYTE PTR SS:[DI] ; Get the digit       }
  373. /$32/$FF          {XOR     BH,BH      ; clear for add                }
  374. /$80/$EB/$30      {SUB     BL,'0'     ; Make binary                  }
  375. /$03/$C3          {ADD     AX,BX      ; Add this digit               }
  376. /$83/$D2/$00      {ADC     DX,0       ; Whole long                   }
  377. /$78/$0A          {JS      ENDSTR     ; Too big, exit.               }
  378. /$72/$08          {JC      ENDSTR                                    }
  379.                   {NXTCHR:                                           }
  380. /$47              {INC     DI; point to next char                    }
  381. /$E2/$C7          {LOOP    CHKCHR     ; again                        }
  382. /$33/$DB          {XOR     BX,BX      ; No error                     }
  383. /$EB/$09/$90      {JMP     RETURN                                    }
  384.                   {ENDSTR:                                           }
  385. /$8D/$9E/strg     {LEA     BX,[strg+bp]; Get addr of string          }
  386. /$2B/$FB          {SUB     DI,BX      ; Get offset to bad char       }
  387. /$8B/$DF          {MOV     BX,DI      ; Set return code              }
  388.                   {RETURN:                                           }
  389. /$0B/$F6          {OR      SI,SI      ; Need to adjust sign?         }
  390. /$79/$0A          {JNS     RETURN1    ; nope                         }
  391. /$F7/$D0          {NOT     AX                                        }
  392. /$F7/$D2          {NOT     DX                                        }
  393. /$83/$C0/$01      {ADD     AX,1                                      }
  394. /$83/$D2/$00      {ADC     DX,0       ; Whole long                   }
  395.                   {RETURN1:                                          }
  396. /$8B/$F3          {MOV     SI,BX      ; Set RC                       }
  397.                   {EXIT:                                             }
  398. /$C4/$BE/rc       {LES     DI,DWORD PTR [BP+rc]                      }
  399. /$26/$89/$35      {MOV     WORD PTR ES:[DI],SI ; Set RC              }
  400. /$C4/$BE/val      {LES     DI,DWORD PTR [BP+val]                     }
  401. /$26/$89/$05      {MOV     WORD PTR ES:[DI],AX ; Low word            }
  402. /$47              {INC     DI                                        }
  403. /$47              {INC     DI                                        }
  404. /$26/$89/$15);    {MOV     WORD PTR ES:[DI],DX ; High Word           }
  405. end;
  406.